import { Injectable, inject } from '@angular/core';
import { TreeNode } from 'primeng/api';
import { v4 as uuid } from 'uuid';
import { g } from './global-data'
import { TransformService } from '@/home/service/transform.service';
import { TrackLineService } from './track-line.service';
import { DataSaveService } from './data-save.service';
import { TrackLine } from '../data-model/track-line.model';
import { WayPoint } from '../data-model/way-point.model';

@Injectable({
    providedIn: 'root'
})
export class KmlParserService {
    transformService = inject(TransformService);
    trackLineService = inject(TrackLineService);
    dataSaveService = inject(DataSaveService);

    is_bad_name(name: string) {
        switch (name) {
            case '':
            case '未命名':
            case 'GPS device':
            case 'Tracks':
                return true;
            default:
                return false;
        }
    }

    parse_kml(kml_string: string, file_name: string): any {
        try {
            const parser = new DOMParser();
            const xml_document = parser.parseFromString(kml_string, "text/xml");

            // 检查是否为有效的XML文件
            if (xml_document.getElementsByTagName("parsererror").length > 0) {
                throw new Error("无效的XML文件格式");
            }

            const kml = xml_document.childNodes[0];
            if (kml.nodeName !== 'kml') {
                throw new Error("无效的KML文件格式");
            }

            const data_list: any[] = [];
            for (const child of kml.childNodes) {
                const tag = child.nodeName.toLowerCase();
                if (tag === 'document' || tag === 'folder') {
                    const folder: TreeNode = {
                        type: 'folder',
                        label: '',
                        expanded: true,
                        children: [],
                    };

                    this.parse_kml_document(child, folder);

                    if (folder.children!.length === 1) {
                        // 如果document下只有一项内容，不建该文件夹，直接将底层内容提升至上一级
                        data_list.push(folder.children![0]);
                        if (this.is_bad_name(folder.children![0].label!)) {
                            folder.children![0].label = file_name;
                        }
                    } else if (folder.children!.length > 1) {
                        if (this.is_bad_name(folder.label!)) {
                            folder.label = file_name;
                        }
                        if (folder.children!.length > 20) {
                            folder.expanded = false;
                        }
                        data_list.push(folder)
                    }
                } else if (tag === 'placemark') {
                    const datatype = this.get_placemark_datatype(child);
                    if (datatype === 'track_line') {
                        const track_line: TrackLine = {
                            type: 'track_line',
                            label: '',
                            uuid: uuid().replace(/-/g, '').toLowerCase(),
                            width: 2,
                            red: 0,
                            green: 0,
                            blue: 255,
                            alpha: 255,
                            draw_endpoints: true,
                            visible: true,
                            has_timestamp: true,
                        }
                        this.parse_track_line(track_line, child);
                        data_list.push(track_line);
                    } else if (datatype === 'way_point') {
                        // 一个文件夹下最多添加100个路点（以及轨迹等节点），多余的忽略
                        if (data_list.length < 100) {
                            const way_point: WayPoint = {
                                type: 'way_point',
                                label: '',
                                uuid: uuid().replace(/-/g, '').toLowerCase(),
                                pin_index: 0,
                                visible: false,
                            }
                            this.parse_way_point(way_point, child);
                            if (!!way_point.lon) {
                                data_list.push(way_point);
                            }
                        }
                    }
                }
            }

            return data_list;
        } catch (error) {
            console.error('解析KML文件失败:', error);
            return [];
        }

    }

    parse_kml_document(kml_document: ChildNode, parent_folder: TreeNode, document_styles: any = {}) {
        for (const child of kml_document.childNodes) {
            const tag = child.nodeName.toLowerCase();

            if (tag === 'name') {
                parent_folder.label = child.textContent || '未命名';
            } else if (tag === 'style') {
                this.parse_kml_document_style(child, document_styles);
            } else if (tag === 'placemark') {
                const datatype = this.get_placemark_datatype(child);
                if (datatype === 'track_line') {
                    const track_line: TrackLine = {
                        type: 'track_line',
                        label: '',
                        uuid: uuid().replace(/-/g, '').toLowerCase(),
                        width: 2,
                        red: 0,
                        green: 0,
                        blue: 255,
                        alpha: 255,
                        draw_endpoints: true,
                        visible: true,
                        has_timestamp: true,
                    }
                    this.parse_track_line(track_line, child, document_styles);
                    parent_folder.children!.push(track_line);
                } else if (datatype === 'way_point') {
                    // 一个文件夹下最多添加100个路点（以及轨迹等节点），多余的忽略
                    if (parent_folder.children!.length < 100) {
                        const way_point: WayPoint = {
                            type: 'way_point',
                            label: '',
                            uuid: uuid().replace(/-/g, '').toLowerCase(),
                            pin_index: 0,
                            visible: false,
                        }
                        this.parse_way_point(way_point, child);
                        if (!!way_point.lon) {
                            parent_folder.children!.push(way_point);
                        }
                    }
                }
            } else if (tag === 'document' || tag === 'folder') {
                const folder: TreeNode = {
                    type: 'folder',
                    label: '',
                    expanded: true,
                    children: [],
                };

                this.parse_kml_document(child, folder, document_styles);

                if (folder.children!.length === 1) {
                    // 如果document下只有一项内容，不建该文件夹，直接将底层内容提升至上一级
                    parent_folder.children!.push(folder.children![0]);
                } else if (folder.children!.length > 1) {
                    if (folder.children!.length > 20) {
                        folder.expanded = false;
                    }
                    parent_folder.children!.push(folder);
                }
            }
        }
    }

    parse_kml_document_style(style: any, document_styles: any) {
        const attributes: NamedNodeMap = style.attributes;
        const style_id = attributes.getNamedItem('id');
        if (!!style_id) {
            for (const child of style.childNodes) {
                if (child.nodeName.toLowerCase() === 'linestyle') {
                    const line_style: any = {};
                    for (const sub_child of child.childNodes) {
                        if (sub_child.nodeName.toLowerCase() === 'color' || sub_child.nodeName.toLowerCase() === 'width') {
                            line_style[sub_child.nodeName.toLowerCase()] = sub_child.textContent;
                        }
                    }

                    if (child.childNodes.length > 0) {
                        document_styles[style_id.value] = line_style;
                    }
                }
            }
        }
    }

    get_placemark_datatype(placemark: ChildNode) {
        let datatype = '';
        for (const child of placemark.childNodes) {
            const tag = child.nodeName.toLowerCase();
            if (tag === 'linestring' || tag === 'track' || tag === 'gx:track') {
                datatype = 'track_line';
            } else if (tag === 'point') {
                datatype = 'way_point';
            }
        }

        return datatype;
    }

    parse_track_line(track_line: TrackLine, placemark: ChildNode, style_ref: any = {}) {
        for (const child of placemark.childNodes) {
            const tag = child.nodeName.toLowerCase();
            switch (tag) {
                case 'name':
                    track_line.label = child.textContent || '未命名';
                    break;
                case 'style':
                    this.parse_style(track_line, child);
                    break;
                case 'styleurl':
                    let style_id = child.textContent;
                    if (style_id!.startsWith('#')) {
                        style_id = style_id!.substring(1);

                        const style = style_ref[style_id];
                        if (!!style) {
                            for (const style_key in style) {
                                if (style_key === 'width') {
                                    track_line.width = parseInt(style[style_key], 10);
                                }
                                if (style_key === 'color') {
                                    // kml中颜色的16进制表示顺序为：透明度，蓝，绿，红，与通常表示正好相反。
                                    track_line.red = parseInt(style[style_key].substring(6, 8), 16);
                                    track_line.green = parseInt(style[style_key].substring(4, 6), 16);
                                    track_line.blue = parseInt(style[style_key].substring(2, 4), 16);
                                    track_line.alpha = parseInt(style[style_key].substring(0, 2), 16);
                                }
                            }
                        }
                    }
                    break;
                case 'linestring':
                    this.parse_line_string(track_line, child);
                    break;
                case 'track':
                case 'gx:track':
                    this.parse_gx_track(track_line, child);
            }
        }

        this.trackLineService.compute_track_line_args(track_line);

        // 只有可见的轨迹才放到渲染缓存
        if (track_line.visible) {
            g.visible_tracks.set(track_line.uuid, track_line);
            g.tracks_to_be_drawn.push(track_line);
        }
        
    }

    parse_style(track_line: TrackLine, style: ChildNode) {
        for (const child of style.childNodes) {
            if (child.nodeName.toLowerCase() === 'linestyle') {
                for (const sub_child of child.childNodes) {
                    const style_key = sub_child.nodeName.toLowerCase();
                    const style_value = sub_child.textContent;
                    if (style_key === 'width') {
                        track_line.width = parseInt(style_value!, 10);
                    }
                    if (style_key === 'color') {
                        // kml中颜色的16进制表示顺序为：透明度，蓝，绿，红，与通常表示正好相反。
                        track_line.red = parseInt(style_value!.substring(6, 8), 16);
                        track_line.green = parseInt(style_value!.substring(4, 6), 16);
                        track_line.blue = parseInt(style_value!.substring(2, 4), 16);
                        track_line.alpha = parseInt(style_value!.substring(0, 2), 16);
                    }
                }

            }
        }
    }

    parse_line_string(track_line: TrackLine, line_string: ChildNode) {
        track_line.has_timestamp = false;
        const track_line_points = []
        for (const child of line_string.childNodes) {
            if (child.nodeName.toLowerCase() === 'coordinates') {
                const coordinates = child.textContent;
                const coordinate_list = coordinates!.trim().split(/[\s\n]+/);
                const timestamp = new Date().toISOString();
                for (const coord_str of coordinate_list) {
                    const coord = coord_str.split(',').map(parseFloat);
                    if (coord.length < 2) {
                        continue;
                    }
                    if (coord.length < 3) {
                        coord.push(0);
                    }

                    const track_point = [
                        coord[0],
                        coord[1],
                        coord[2],
                        timestamp,
                        this.transformService.get_fpx_from_longitude(coord[0]),
                        this.transformService.get_fpy_from_latitude(coord[1])
                    ]
                    track_line_points.push(track_point);
                }
            }
        }

        g.track_line_points_cache.set(track_line.uuid, track_line_points);
        this.dataSaveService.save_track_data(track_line.uuid!);
    }

    parse_gx_track(track_line: TrackLine, gx_track: ChildNode) {
        track_line.has_timestamp = true;
        const timestamp_list: string[] = [];
        const coord_str_list: string[] = [];

        for (const child of gx_track.childNodes) {
            const tag = child.nodeName.toLowerCase();
            if (tag === 'when') {
                timestamp_list.push(child.textContent!);
            } else if (tag === 'gx:coord' || tag === 'coord') {
                coord_str_list.push(child.textContent!);
            }
        }

        const track_line_points = []
        const num_point = Math.min(timestamp_list.length, coord_str_list.length);
        for (let i = 0; i < num_point; i++) {
            const coord = coord_str_list[i].trim().split(' ').map(parseFloat);
            const track_point = [
                coord[0],
                coord[1],
                coord[2],
                timestamp_list[i],
                this.transformService.get_fpx_from_longitude(coord[0]),
                this.transformService.get_fpy_from_latitude(coord[1])
            ]
            track_line_points.push(track_point);
        }

        g.track_line_points_cache.set(track_line.uuid, track_line_points);
        this.dataSaveService.save_track_data(track_line.uuid!);
    }

    parse_way_point(way_point: WayPoint, placemark: ChildNode) {
        for (const child of placemark.childNodes) {
            const tag = child.nodeName.toLowerCase();
            if (tag === 'name') {
                way_point.label = child.textContent || '未命名';
            } else if (tag === 'point') {
                for (const subchild of child.childNodes) {
                    if (subchild.nodeName.toLowerCase() == 'coordinates') {
                        const wpt = subchild.textContent!.split(',');
                        if (wpt.length > 1) {
                            way_point.lon = parseFloat(wpt[0]);
                            way_point.lat = parseFloat(wpt[1]);
                            if (wpt.length > 2) {
                                way_point.alt = parseFloat(wpt[1]);
                            }

                            way_point.fpx = this.transformService.get_fpx_from_longitude(way_point.lon);
                            way_point.fpy = this.transformService.get_fpy_from_latitude(way_point.lat);
                        }
                    }
                }
            } else if (tag === 'timestamp') {
                for (const subchild of child.childNodes) {
                    if (subchild.nodeName.toLowerCase() == 'when') {
                        way_point.timestamp = subchild.textContent?.trim();
                    }
                }
            }

        }

        // 路点与轨迹共用一个渲染缓存
        if (way_point.visible) {
            g.visible_tracks.set(way_point.uuid, way_point);
            g.tracks_to_be_drawn.push(way_point);
        }
    }

}
